package com.koron.device.controller;


import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageHelper;
import com.koron.bean.base.Response;
import com.koron.bean.system.staff.vo.EamUser;
import com.koron.common.core.annocation.CasUser;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.CommonUtils;
import com.koron.common.core.util.ExportExcelUtil;
import com.koron.common.core.util.TreeUtils;
import com.koron.device.bean.Equipment;
import com.koron.device.bean.EquipmentLocation;
import com.koron.device.bean.EquipmentLocationQuery;
import com.koron.device.bean.LoctionExcel;
import com.koron.device.bean.template.ImPMsgDto;
import com.koron.device.bean.template.LocationErrorMsg;
import com.koron.device.bean.template.LocationTemplate;
import com.koron.device.mapper.EquipmentLocationMapper;
import com.koron.device.service.EquipmentLocationService;
import com.koron.device.utils.EqtempInitData;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.koron.ebs.mybatis.ADOConnection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 设备管理-位置管理{@code EquipmentLocationController} 控制层
 *
 * <p>主要提供：新增、删除、修改、查询位置树、移动节点、查询单条数据</p>
 *
 * @Author 朱超
 * @Date 2021/7/23
 */
@Api(tags = "设备位置管理")
@RestController
@RequestMapping("/device/location")
@Slf4j
public class EquipmentLocationController {

    private String getCurrDs() {
        return ThreadLocalContext.get().getCurrDs();
    }

    @Autowired
    EquipmentLocationService equipmentLocationService;

    /**
     * 新增数据
     *
     * @param equipmentLocation
     * @return Resposnse对象
     * @version 1.0
     * @see Response
     */
    @ApiOperation(value = "新增位置")
    @PostMapping("/insert")
    public Response insert(@RequestBody EquipmentLocation equipmentLocation) {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "checkBeforeInsert", Response.class, equipmentLocation);
    }

    /**
     * 逻辑删除位置
     *
     * @param id
     * @return Resposnse对象
     * @version 1.0
     * @see Response
     */
    @ApiOperation(value = "删除位置")
    @GetMapping("/delete")
    public Response delete(String id) {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "logicDelete", Response.class, id);
    }

    @ApiOperation(value = "根据位置条件查询列表")
    @GetMapping("/queryList")
    public Response queryList(EquipmentLocationQuery query) {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "queryList", Response.class, query);
    }

    /**
     * 修改位置
     *
     * @param equipmentLocation
     * @return Resposnse对象
     * @version 1.0
     * @see Response
     */
    @ApiOperation(value = "修改位置")
    @PutMapping("/update")
    public Response update(@RequestBody EquipmentLocation equipmentLocation) {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "checkBeforeUpdate", Response.class, equipmentLocation);
    }

    /**
     * 查询位置管理树状结构
     *
     * @return Resposnse对象
     * @version 1.0
     * @see Response
     */
    @ApiOperation(value = "查询位置管理树状结构")
    @GetMapping("/getTree")
    public Response getTree(@RequestParam(value = "status", required = false) String status) {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "getTree", Response.class, status);
    }

    /**
     * 移动节点
     *
     * @param id       当前节点id
     * @param parentId 需要移动到的节点id
     * @return Resposnse对象
     * @version 1.0
     * @see Response
     */
    @ApiOperation(value = "移动节点")
    @GetMapping("/moveNode")
    public Response moveNode(String id, String parentId, Integer sort) {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "moveNode", Response.class, id, parentId, sort);
    }

    /**
     * 查询单条数据
     *
     * @param id 当前节点id
     * @return Resposnse对象
     * @version 1.0
     * @see Response
     */
    @ApiOperation(value = "查询单条数据")
    @GetMapping("/getById")
    public Response getById(String id) {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "getById", Response.class, id);
    }

    @ApiOperation(value = "根据位置id分页查询设备")
    @GetMapping("/getEquipmentById")
    public Response getEquipmentById(String locationId, int page, int pageSize) {
        PageHelper.startPage(page, pageSize);
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "getEquipmentById", Response.class, locationId);
    }

    /**
     * 查询单条数据
     *
     * @param ids 当前节点id
     * @return Resposnse对象
     * @version 1.0
     * @see Response
     */
    @ApiOperation(value = "查询单条数据")
    @PostMapping("/getByIdWithoutEquipment")
    public Response getByIdWithoutEquipment(@RequestBody List<String> ids) {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "getByIdWithoutEquipment", Response.class, ids);
    }

    /**
     * 根据设备id查询设备位置，设备不存在位置时，返回data为空
     *
     * @param equipId 当前节点id
     * @return Resposnse对象
     * @version 1.0
     * @see Response
     */
    @ApiOperation(value = "根据设备id查询设备位置，设备不存在位置时，返回data为空")
    @GetMapping("/getByEquipId")
    @ApiImplicitParam(name = "equipId", value = "设备id")
    public Response getByEquipId(String equipId) {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "getByEquipId", Response.class, equipId);
    }

    /**
     * 根据orgId查询所有关联数据中，对应的第一个最上级数据的父级id
     *
     * @param orgId 关联组织id
     * @return Resposnse对象
     * @version 1.0
     * @see Response
     */
    @ApiOperation(value = "据orgId查询所有关联数据中，对应的第一个最上级数据的父级id")
    @GetMapping("/getParentIdByOrgId")
    public Response getParentIdByOrgId(String orgId) {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "getParentIdByOrgId", Response.class, orgId);
    }

    @ApiOperation(value = "将组织数据(无树结构)同步到备用表中")
    @GetMapping("/initializeFirst")
    public Response initializeFirst() {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "initializeFirst", Response.class);
    }

    @ApiOperation(value = "将组织数据的parentId更新")
    @GetMapping("/initializeSecond")
    public Response initializeSecond() {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "initializeSecond", Response.class);
    }

    @ApiOperation(value = "将组织数据的parentId更新")
    @GetMapping("/initializeTwoPointFive")
    public Response initializeTwoPointFive() {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "initializeTwoPointFive", Response.class);
    }

    @ApiOperation(value = "将1.0的位置信息从安全管理中心初始化到数据库中")
    @GetMapping("/initializeThird")
    public Response initializeThird() {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "initializeThird", Response.class);
    }

    @ApiOperation(value = "将所有数据的parentId，parentName，level，levelCode，levelPath更新")
    @GetMapping("/initializeFourth")
    public Response initializeFourth() {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "initializeFourth", Response.class);
    }

    @ApiOperation(value = "刷新经纬度")
    @GetMapping("/refreshLatLon")
    public Response refreshLatLon() {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "refreshLatLon", Response.class);
    }

    @ApiOperation(value = "获取设备范围内的其他位置")
    @GetMapping("/getRangeLocation")
    public Response getRangeLocation(EquipmentLocationQuery query) {
        return ADOConnection.runTask(getCurrDs(), equipmentLocationService, "getRangeLocation", Response.class, query);
    }

    @GetMapping("/getLeftUpperLocationByOrgId")
    @ApiOperation(value = "获取同组织下，最左上的位置")
    public Response<Equipment> getLeftUpperLocationByOrgId(@CasUser @ApiIgnore EamUser user, String orgId) {
        return ADOConnection.runTask(user.getCurrDs(), equipmentLocationService, "getLeftUpperLocationByOrgId", Response.class, orgId);
    }

    @ApiOperation(value = "导出所有位置")
    @GetMapping("/export")
    @ApiImplicitParam(value = "设备id，不传导出全部", name = "equipmentId")
    public void export(@CasUser @ApiIgnore EamUser user, HttpServletResponse resp, @RequestParam(required = false) String locationId) {
        List<LocationTemplate> excels = ADOConnection.runTask(user.getCurrDs(), equipmentLocationService, "export", List.class, locationId);
        ExportExcelUtil.exportExcel(excels, LocationTemplate.class, "位置列表", resp);
    }

    @ApiOperation(value = "导出位置模板")
    @GetMapping("/downLocationTemplate")
    public void downLocationTemplate(HttpServletResponse rsp) {
        List<LocationTemplate> list = new ArrayList<>();
        try {
            EqtempInitData.initLocationData(list);
            ExportExcelUtil.exportExcel(list, LocationTemplate.class, "位置模板", rsp);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @ApiOperation(value = "导入位置模板")
    @PostMapping("/importLocation")
    public Response<ImPMsgDto> importLocation(@CasUser @ApiIgnore EamUser user, @RequestParam("file") MultipartFile multipartFile, @RequestParam(value = "id", required = false) String id) throws Exception {
        ExcelImportResult<LocationTemplate> result;
        ImportParams params = new ImportParams();
        // 表头设置为2行
        params.setHeadRows(1);
        // 标题行设置为0行，默认是0，可以不设置
        params.setTitleRows(0);
        result = ExcelImportUtil.importExcelMore(multipartFile.getInputStream(), LocationTemplate.class, params);
        List<LocationTemplate> list = result.getList();

        //获取父级位置
        EquipmentLocation parenLo = ADOConnection.runTask(user.getCurrDs(), sessionFactory -> {
            //不传父id默认在 系统默认根节点下建立树结构
            String parentId = StrUtil.isBlank(id) ? "0" : id;
            Map<String, List<LocationTemplate>> groupBymap = list.stream().collect(Collectors.groupingBy(LocationTemplate::getParentCode));
            Set<String> key = groupBymap.keySet();
            if (key.size() == 1) {
                return sessionFactory.getMapper(EquipmentLocationMapper.class).getByCode(CollUtil.get(key, 0));
            }

            return sessionFactory.getMapper(EquipmentLocationMapper.class).getById(parentId);
        }, EquipmentLocation.class);

        //数据库所有位置记录
        List<EquipmentLocation> allLocationlist = ADOConnection.runTask(user.getCurrDs(), factory -> {
            return factory.getMapper(EquipmentLocationMapper.class).queryByDeleteFlag(0);
        }, List.class);
        Map<String, String> codeNamemap = allLocationlist.stream().collect(Collectors.toMap(EquipmentLocation::getCode, EquipmentLocation::getName));//位置编码、名称map

        //数据校验
        List<LocationErrorMsg> checklist = ADOConnection.runTask(user.getCurrDs(), equipmentLocationService, "checkLocation", List.class, list, codeNamemap);

        if (checklist.stream().anyMatch(c -> StrUtil.isNotBlank(c.getErrorMsg()))) {
            String time = String.valueOf(DateUtil.currentSeconds());
            String fileName = ExportExcelUtil.saveExcel(checklist, LocationErrorMsg.class, "错误信息" + time + ".xls");
            return Response.ok(new ImPMsgDto("ERROR", "导入异常", fileName));
        }

        //数据构建 入库
        ADOConnection.runTask(user.getCurrDs(), equipmentLocationService, "buildLocation", List.class, checklist, parenLo, allLocationlist);


        return Response.ok(new ImPMsgDto("SUCCESS", "导入成功", ""));
    }

    @ApiOperation(value = "导出位置信息")
    @GetMapping("/derivedLocationInformation")
    public void derivedLocationInformation(HttpServletResponse resp,  String fileName) {
        List<LoctionExcel> list = ADOConnection.runTask(getCurrDs(), factory -> {
            EquipmentLocationMapper lcationmapper = factory.getMapper(EquipmentLocationMapper.class);
            // 获取节点下的所有设备及其子设备(不含隐藏的根节点)
            List<EquipmentLocation> location = lcationmapper.queryAll();
            List<LoctionExcel> excels = new ArrayList<>();
            TreeUtils<EquipmentLocation, String> tree = new TreeUtils<>(location, EquipmentLocation::getId, EquipmentLocation::getParentId, EquipmentLocation::setChildren);
            List<EquipmentLocation> build = tree.build();
            //根节点生成序号
            for (int i = 0; i < build.size(); i++) {
                EquipmentLocation treeVO = build.get(i);
                String levelPath = i + 1 + "";
                treeVO.setLevelPath(levelPath);
                recursiveLoopCreateSeqNum(treeVO.getChildren(), levelPath);
            }
            recursionEq(build, excels);

            return excels;
        }, List.class);
        ExportExcelUtil.exportExcel(list, LoctionExcel.class, "位置节点信息.xlsx", resp);
        return;
    }

    void recursiveLoopCreateSeqNum(List<EquipmentLocation> treeList, String levelPath) {
        if (null == treeList || treeList.size() < 1) {
            return;
        }
        for (int i = 0; i < treeList.size(); i++) {
            EquipmentLocation treeVO = treeList.get(i);
            String childLevelPath = levelPath + "." + (i + 1);
            treeVO.setLevelPath(childLevelPath);
            recursiveLoopCreateSeqNum(treeVO.getChildren(), childLevelPath);
        }
    }

    // 正序递归 实体
    public void recursionEq(List<EquipmentLocation> jsonToList, List<LoctionExcel> excels) {
        for (EquipmentLocation vo: jsonToList) {
            LoctionExcel convert = Convert.convert(LoctionExcel.class, vo);
            convert.setLevelCode(vo.getLevelPath());
            excels.add(convert);
            if (CollUtil.isNotEmpty(vo.getChildren())) {
                recursionEq(vo.getChildren(), excels);
            }
        }
    }

    @ApiOperation(value = "测试中英文切换")
    @PutMapping("/testZhCN")
    public Response testZhCN() {
//        Assert.isFalse(true, CommonUtils.msgFormat("异常简体","異常","error"));
//        Assert.isFalse(true, "异常简体");
//        return Response.ok();
        return Response.ok(CommonUtils.msgFormat("简体成功","繁体成功","success"),"");
    }

}
